#region License
///License Begin
///This program has been developed by: Rodolfo Grave de Peralta, 
///Copyright (C) 2007 Rodolfo Grave de Peralta
///This program is free software; you can redistribute it and/or modify
///it under the terms of the GNU General Public License as published by
///the Free Software Foundation; either version 2 of the License, or
///(at your option) any later version.
///
///This program is distributed in the hope that it will be useful,
///but WITHOUT ANY WARRANTY; without even the implied warranty of
///MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
///GNU General Public License for more details.
///
///You should have received a copy of the GNU General Public License
///along with this program; if not, write to the Free Software
///Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
///License End
#endregion

using System;
using System.Windows;
using System.Data;
using System.Xml;
using System.Configuration;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Security.Principal;
using System.Diagnostics;
using System.Windows.Threading;

using TEAM.TimeTracking.Model;
using Db4objects.Db4o;

namespace TEAM.TimeTracking.View
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>

    public partial class App : System.Windows.Application
    {

        public App()
        {
            currentConfig = new XmlConfig();
        }

        public static App CurrentApp
        {
            get
            {
                return (App)Current;
            }
        }

        protected IConfig currentConfig;

        public IConfig CurrentConfig
        {
            get { return currentConfig; }
            set { currentConfig = value; }
        }

        protected IObjectContainer database;

        public IObjectContainer Database
        {
            get { return database; }
        }

        public WidgetWindow MainWidgetWindow
        {
            get
            {
                return MainWindow as WidgetWindow;
            }
        }

        protected ReportWindow mainReportWindow;

        public ReportWindow MainReportWindow
        {
            get { return mainReportWindow; }
        }

        public void ShowReportWindow()
        {
            if (mainReportWindow == null || !mainReportWindow.IsVisible)
            {
                mainReportWindow = new ReportWindow();
            }
            mainReportWindow.Show();
            mainReportWindow.WindowState = WindowState.Normal;
            mainReportWindow.Activate();
        }

        protected AdminWindow mainAdminWindow;

        public AdminWindow MainAdminWindow
        {
            get { return mainAdminWindow; }
        }

        public void ShowAdminWindow()
        {
            if (mainAdminWindow == null || !mainAdminWindow.IsVisible)
            {
                mainAdminWindow = new AdminWindow();
            }
            mainAdminWindow.Show();
            mainAdminWindow.WindowState = WindowState.Normal;
            mainAdminWindow.Activate();
        }

        protected SettingsWindow mainSettingsWindow;

        public SettingsWindow MainSettingsWindow
        {
            get { return mainSettingsWindow; }
        }

        public void ShowSettingsWindow()
        {
            if (mainSettingsWindow == null || !mainSettingsWindow.IsVisible)
            {
                mainSettingsWindow = new SettingsWindow();
            }
            mainSettingsWindow.Show();
            mainSettingsWindow.WindowState = WindowState.Normal;
            mainSettingsWindow.Activate();
        }

        protected AboutWindow mainAboutWindow;

        public AboutWindow MainAboutWindow
        {
            get { return mainAboutWindow; }
        }

        public void ShowAboutWindow()
        {
            if (mainAboutWindow == null || !mainAboutWindow.IsVisible)
            {
                mainAboutWindow = new AboutWindow();
            }
            mainAboutWindow.Show();
            mainAboutWindow.WindowState = WindowState.Normal;
            mainAboutWindow.Activate();
        }

        protected DataModel currentModel;

        public DataModel CurrentModel
        {
            get { return currentModel; }
            set { currentModel = value; }
        }

        public void LogException(Exception ex)
        {
            System.Diagnostics.EventLog.WriteEntry("TimeTracker", "ERROR: " + ex.ToString());
        }

        protected void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
        {
            e.Handled = true;
            if (MessageBox.Show("Something has gone wrong. " + e.Exception.Message + ". Probably your last operation was not completed correctly. Do you want to leave the application?", "ERROR", MessageBoxButton.YesNo, MessageBoxImage.Error, MessageBoxResult.No) == MessageBoxResult.Yes)
            {
                Database.Close();
                // Make a backup of the database
                if (!CurrentConfig.UseRemoteConnection && File.Exists(CurrentConfig.LocalDatabasePath))
                {
                    DateTime now = DateTime.Now;
                    string suffix = now.Year.ToString() + now.Month.ToString() + now.Day.ToString() + now.Hour.ToString("00") + now.Minute.ToString("00") + now.Second.ToString("00");
                    File.Copy(CurrentConfig.LocalDatabasePath, CurrentConfig.LocalDatabasePath + "." + suffix + ".crash.backup", true);
                }
                Shutdown();
            }
        }

        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            StartingWindow startingWindow = new StartingWindow();
            startingWindow.Message = "Starting up... please, wait";
            startingWindow.Show();

            Db4oFactory.Configure().ActivationDepth(1000);
            Db4oFactory.Configure().UpdateDepth(1000);

            bool ok = true;

            if (CurrentConfig.UseRemoteConnection)
            {
                try
                {
                    database = Db4oFactory.OpenClient(
                        CurrentConfig.RemoteDBHostName,
                        CurrentConfig.RemoteDBPort,
                        CurrentConfig.RemoteDBUser,
                        CurrentConfig.RemoteDBPassword);
                }
                catch (Exception ex)
                {
                    ok = false;
                    LogException(ex);
                }
            }
            else
            {
                if (!File.Exists(CurrentConfig.LocalDatabasePath))
                {
                    startingWindow.Message = "Running for the first time... wait just a moment";
                }
                try
                {
                    database = Db4oFactory.OpenFile(CurrentConfig.LocalDatabasePath);
                }
                catch (Exception ex)
                {
                    ok = false;
                    LogException(ex);
                }
            }

            try
            {
                if (database == null)
                {
                    ok = false;
                }
                else
                {
                    IList<DataModel> stored = database.Query<DataModel>();
                    if (stored.Count == 0)
                    {
                        currentModel = new DataModel();
                        FillModelWithDefaultData();
                        Database.Set(CurrentModel);
                        Database.Commit();
                    }
                    else
                    {
                        currentModel = stored[0];

                        UpdateDatabaseContent();

                        WindowsIdentity currentWindowsUser = WindowsIdentity.GetCurrent();

                        IList<TEAM.TimeTracking.Model.User> users = database.Query<TEAM.TimeTracking.Model.User>(
                            new Predicate<TEAM.TimeTracking.Model.User>(
                            delegate(TEAM.TimeTracking.Model.User user)
                            {
                                return user != null && user.Id.Equals(currentWindowsUser.User.Value);
                            }));

                        if (users.Count == 0)
                        {
                            TEAM.TimeTracking.Model.User user = new TEAM.TimeTracking.Model.User();
                            user.Name = currentWindowsUser.Name;
                            user.Id = currentWindowsUser.User.Value;
                            currentModel.Users.Add(user);
                            currentModel.CurrentUser = user;
                            Database.Set(currentModel.Users);
                            Database.Commit();
                        }
                        else
                        {
                            currentModel.CurrentUser = users[0];
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                ok = false;
                LogException(ex);
            }

            if (ok)
            {
                MainWindow = new WidgetWindow();

                MainWindow.Left = System.Windows.SystemParameters.PrimaryScreenWidth - MainWindow.Width - 60;
                MainWindow.Top = 0;

                ConfirmDefaultTaskWindow w = new ConfirmDefaultTaskWindow();
                w.IsArriving = true;

                if (startingWindow != null)
                {
                    startingWindow.Close();
                }
                w.ShowDialog();
                if (MainWindow != null)
                {
                    MainWindow.Show();
                }
            }
            else
            {
                ConfigurationErrorWindow errWindow = new ConfigurationErrorWindow();
                errWindow.ShowDialog();
                //errWindow.Message = "Can not access the database. Please, check your settings";
                MainWindow = new SettingsWindow();
                if (startingWindow != null)
                {
                    startingWindow.Close();
                }
                MainWindow.ShowDialog();
                OnStartup(e);
            }
        }

        /// <summary>
        /// Update the database from the previous version
        /// </summary>
        protected void UpdateDatabaseContent()
        {
            // Ensure the user's tasks and projects are in the model
            bool dbNeedsUpdate = false;
            if (CurrentModel.Tasks == null)
            {
                CurrentModel.Tasks = new System.Collections.ObjectModel.ObservableCollection<Task>();
            }
            if (CurrentModel.Projects == null)
            {
                CurrentModel.Projects = new System.Collections.ObjectModel.ObservableCollection<Project>();
            }
            foreach (TEAM.TimeTracking.Model.User u in CurrentModel.Users)
            {
                foreach (Project p in u.Projects)
                {
                    foreach (Task t in p.Tasks)
                    {
                        if (!CurrentModel.Tasks.Contains(t))
                        {
                            CurrentModel.Tasks.Add(t);
                            dbNeedsUpdate = true;
                        }
                    }
                    if (!CurrentModel.Projects.Contains(p))
                    {
                        CurrentModel.Projects.Add(p);
                        dbNeedsUpdate = true;
                    }
                }
            }
            if (dbNeedsUpdate)
            {
                Database.Set(CurrentModel);
                Database.Commit();
            }
            //// Check if the database contains the ReportToday and ReportThisYear
            //bool foundToday = false;
            //bool foundThisYear = false;
            //int i = 0;
            //for (i = 0; i < CurrentModel.Reports.Count && (!foundThisYear || !foundToday); i++)
            //{
            //    if (CurrentModel.Reports[i] is ReportToday)
            //    {
            //        foundToday = true;
            //    }
            //    if (CurrentModel.Reports[i] is ReportThisYear)
            //    {
            //        foundThisYear = true;
            //    }
            //}
            //Report r;
            //if (!foundToday)
            //{
            //    r = new ReportToday();
            //    r.Name = "Today";
            //    CurrentModel.Reports.Add(r);
            //}
            //if (!foundThisYear)
            //{
            //    r = new ReportThisYear();
            //    r.Name = "This Year";
            //    CurrentModel.Reports.Insert(1, r);
            //}
            //if (!foundToday || !foundThisYear)
            //{
            //    Database.Set(CurrentModel.Reports);
            //    Database.Commit();
            //}
        }

        public void GracefulShutDown()
        {
            ByeWindow bye = new ByeWindow();
            ConfirmDefaultTaskWindow w = new ConfirmDefaultTaskWindow();
            w.IsLeaving = true;
            w.ShowDialog();
            bye.Show();
            Thread.Sleep(2000);
            bye.Close();

            if (Database != null && !Database.Ext().IsClosed())
            {
                //Database.Set(CurrentModel);
                Database.Close();
            }
            Shutdown();
        }

        protected override void OnSessionEnding(SessionEndingCancelEventArgs e)
        {
            GracefulShutDown();
            base.OnSessionEnding(e);
        }

        protected void FillModelWithDefaultData()
        {
            TEAM.TimeTracking.Model.User u = new TEAM.TimeTracking.Model.User();
            WindowsIdentity currentWindowsUser = WindowsIdentity.GetCurrent();
            u.Name = currentWindowsUser.Name;
            u.Id = currentWindowsUser.User.Value;

            Task t = new Task();
            t.Name = "having lunch";
            t.IsWorkingTime = false;
            u.Tasks.Add(t);

            t = new Task();
            t.Name = "having breakfast";
            t.IsWorkingTime = false;
            u.Tasks.Add(t);

            u.StartTaskNow(t, null);

            t = new Task();
            t.Name = "being at home";
            t.IsWorkingTime = false;
            u.Tasks.Add(t);
            u.DefaultTaskWhenLeaving = t;

            Project p = new Project();
            p.IsActive = true;
            p.Name = "Project 1";

            t = new Task();
            t.Name = "working in-place";
            t.IsWorkingTime = true;
            p.AddTask(t);

            u.DefaultTaskWhenArriving = t;

            t = new Task();
            t.Name = "working outside";
            t.IsWorkingTime = true;
            p.AddTask(t);

            u.Projects.Add(p);

            CurrentModel.Users.Add(u);
            CurrentModel.CurrentUser = u;

            Report r = new ReportIncludeAll();
            r.Name = "All";

            currentModel.Reports.Add(r);

            r = new ReportThisMonth();
            r.Name = "This Month";

            currentModel.Reports.Add(r);

            r = new ReportThisYear();
            r.Name = "This Year";

            currentModel.Reports.Add(r);

            r = new ReportThisWeek();
            r.Name = "This Week";

            currentModel.Reports.Add(r);

            r = new ReportToday();
            r.Name = "Today";

            currentModel.Reports.Add(r);
        }
    }
}